1   /*
2    * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package sun.nio.cs.ext;
27  
28  import java.util.Collections;
29  import java.util.ArrayList;
30  import java.util.HashMap;
31  import java.util.List;
32  import java.util.Map;
33  import java.nio.charset.*;
34  
35  final class CompoundTextSupport {
36  
37      private static final class ControlSequence {
38  
39          final int hash;
40          final byte[] escSequence;
41          final byte[] encoding;
42  
43          ControlSequence(byte[] escSequence) {
44              this(escSequence, null);
45          }
46          ControlSequence(byte[] escSequence, byte[] encoding) {
47              if (escSequence == null) {
48                  throw new NullPointerException();
49              }
50  
51              this.escSequence = escSequence;
52              this.encoding = encoding;
53  
54              int hash = 0;
55              int length = escSequence.length;
56  
57              for (int i = 0; i < escSequence.length; i++) {
58                  hash += (((int)escSequence[i]) & 0xff) << (i % 4);
59              }
60              if (encoding != null) {
61                  for (int i = 0; i < encoding.length; i++) {
62                      hash += (((int)encoding[i]) & 0xff) << (i % 4);
63                  }
64                  length += 2 /* M L */ + encoding.length + 1 /* 0x02 */;
65              }
66  
67              this.hash = hash;
68  
69              if (MAX_CONTROL_SEQUENCE_LEN < length) {
70                  MAX_CONTROL_SEQUENCE_LEN = length;
71              }
72          }
73  
74          public boolean equals(Object obj) {
75              if (this == obj) {
76                  return true;
77              }
78              if (!(obj instanceof ControlSequence)) {
79                  return false;
80              }
81              ControlSequence rhs = (ControlSequence)obj;
82              if (escSequence != rhs.escSequence) {
83                  if (escSequence.length != rhs.escSequence.length) {
84                      return false;
85                  }
86                  for (int i = 0; i < escSequence.length; i++) {
87                      if (escSequence[i] != rhs.escSequence[i]) {
88                          return false;
89                      }
90                  }
91              }
92              if (encoding != rhs.encoding) {
93                  if (encoding == null || rhs.encoding == null ||
94                      encoding.length != rhs.encoding.length)
95                  {
96                      return false;
97                  }
98                  for (int i = 0; i < encoding.length; i++) {
99                      if (encoding[i] != rhs.encoding[i]) {
100                         return false;
101                     }
102                 }
103             }
104             return true;
105         }
106 
107         public int hashCode() {
108             return hash;
109         }
110 
111         ControlSequence concatenate(ControlSequence rhs) {
112             if (encoding != null) {
113                 throw new IllegalArgumentException
114                     ("cannot concatenate to a non-standard charset escape " +
115                      "sequence");
116             }
117 
118             int len = escSequence.length + rhs.escSequence.length;
119             byte[] newEscSequence = new byte[len];
120             System.arraycopy(escSequence, 0, newEscSequence, 0,
121                              escSequence.length);
122             System.arraycopy(rhs.escSequence, 0, newEscSequence,
123                              escSequence.length, rhs.escSequence.length);
124             return new ControlSequence(newEscSequence, rhs.encoding);
125         }
126     }
127 
128     static int MAX_CONTROL_SEQUENCE_LEN;
129 
130     /**
131      * Maps a GL or GR escape sequence to an encoding.
132      */
133     private static final Map<ControlSequence, String> sequenceToEncodingMap;
134 
135     /**
136      * Indicates whether a particular encoding wants the high bit turned on
137      * or off.
138      */
139     private static final Map<ControlSequence, Boolean> highBitsMap;
140 
141     /**
142      * Maps an encoding to an escape sequence. Rather than manage two
143      * converters in CharToByteCOMPOUND_TEXT, we output escape sequences which
144      * modify both GL and GR if necessary. This makes the output slightly less
145      * efficient, but our code much simpler.
146      */
147     private static final Map<String, ControlSequence> encodingToSequenceMap;
148 
149     /**
150      * The keys of 'encodingToSequenceMap', sorted in preferential order.
151      */
152     private static final List<String> encodings;
153 
154     static {
155         HashMap<ControlSequence, String> tSequenceToEncodingMap =
156             new HashMap<>(33, 1.0f);
157         HashMap<ControlSequence, Boolean> tHighBitsMap =
158             new HashMap<>(31, 1.0f);
159         HashMap<String, ControlSequence> tEncodingToSequenceMap =
160             new HashMap<>(21, 1.0f);
161         ArrayList<String> tEncodings = new ArrayList<>(21);
162 
163         if (!(isEncodingSupported("US-ASCII") &&
164               isEncodingSupported("ISO-8859-1")))
165         {
166             throw new ExceptionInInitializerError
167                 ("US-ASCII and ISO-8859-1 unsupported");
168         }
169 
170         ControlSequence leftAscii = // high bit off, leave off
171             new ControlSequence(new byte[] { 0x1B, 0x28, 0x42 });
172         tSequenceToEncodingMap.put(leftAscii, "US-ASCII");
173         tHighBitsMap.put(leftAscii, Boolean.FALSE);
174 
175         {
176             ControlSequence rightAscii = // high bit on, turn off
177                 new ControlSequence(new byte[] { 0x1B, 0x29, 0x42 });
178             tSequenceToEncodingMap.put(rightAscii, "US-ASCII");
179             tHighBitsMap.put(rightAscii, Boolean.FALSE);
180         }
181 
182         {
183             ControlSequence rightHalf = // high bit on, leave on
184                 new ControlSequence(new byte[] { 0x1B, 0x2D, 0x41 });
185             tSequenceToEncodingMap.put(rightHalf, "ISO-8859-1");
186             tHighBitsMap.put(rightHalf, Boolean.TRUE);
187 
188             ControlSequence fullSet = leftAscii.concatenate(rightHalf);
189             tEncodingToSequenceMap.put("ISO-8859-1", fullSet);
190             tEncodings.add("ISO-8859-1");
191         }
192         if (isEncodingSupported("ISO-8859-2")) {
193             ControlSequence rightHalf = // high bit on, leave on
194                 new ControlSequence(new byte[] { 0x1B, 0x2D, 0x42 });
195             tSequenceToEncodingMap.put(rightHalf, "ISO-8859-2");
196             tHighBitsMap.put(rightHalf, Boolean.TRUE);
197 
198             ControlSequence fullSet = leftAscii.concatenate(rightHalf);
199             tEncodingToSequenceMap.put("ISO-8859-2", fullSet);
200             tEncodings.add("ISO-8859-2");
201         }
202         if (isEncodingSupported("ISO-8859-3")) {
203             ControlSequence rightHalf = // high bit on, leave on
204                 new ControlSequence(new byte[] { 0x1B, 0x2D, 0x43 });
205             tSequenceToEncodingMap.put(rightHalf, "ISO-8859-3");
206             tHighBitsMap.put(rightHalf, Boolean.TRUE);
207 
208             ControlSequence fullSet = leftAscii.concatenate(rightHalf);
209             tEncodingToSequenceMap.put("ISO-8859-3", fullSet);
210             tEncodings.add("ISO-8859-3");
211         }
212         if (isEncodingSupported("ISO-8859-4")) {
213             ControlSequence rightHalf = // high bit on, leave on
214                 new ControlSequence(new byte[] { 0x1B, 0x2D, 0x44 });
215             tSequenceToEncodingMap.put(rightHalf, "ISO-8859-4");
216             tHighBitsMap.put(rightHalf, Boolean.TRUE);
217 
218             ControlSequence fullSet = leftAscii.concatenate(rightHalf);
219             tEncodingToSequenceMap.put("ISO-8859-4", fullSet);
220             tEncodings.add("ISO-8859-4");
221         }
222         if (isEncodingSupported("ISO-8859-5")) {
223             ControlSequence rightHalf = // high bit on, leave on
224                 new ControlSequence(new byte[] { 0x1B, 0x2D, 0x4C });
225             tSequenceToEncodingMap.put(rightHalf, "ISO-8859-5");
226             tHighBitsMap.put(rightHalf, Boolean.TRUE);
227 
228             ControlSequence fullSet = leftAscii.concatenate(rightHalf);
229             tEncodingToSequenceMap.put("ISO-8859-5", fullSet);
230             tEncodings.add("ISO-8859-5");
231         }
232         if (isEncodingSupported("ISO-8859-6")) {
233             ControlSequence rightHalf = // high bit on, leave on
234                 new ControlSequence(new byte[] { 0x1B, 0x2D, 0x47 });
235             tSequenceToEncodingMap.put(rightHalf, "ISO-8859-6");
236             tHighBitsMap.put(rightHalf, Boolean.TRUE);
237 
238             ControlSequence fullSet = leftAscii.concatenate(rightHalf);
239             tEncodingToSequenceMap.put("ISO-8859-6", fullSet);
240             tEncodings.add("ISO-8859-6");
241         }
242         if (isEncodingSupported("ISO-8859-7")) {
243             ControlSequence rightHalf = // high bit on, leave on
244                 new ControlSequence(new byte[] { 0x1B, 0x2D, 0x46 });
245             tSequenceToEncodingMap.put(rightHalf, "ISO-8859-7");
246             tHighBitsMap.put(rightHalf, Boolean.TRUE);
247 
248             ControlSequence fullSet = leftAscii.concatenate(rightHalf);
249             tEncodingToSequenceMap.put("ISO-8859-7", fullSet);
250             tEncodings.add("ISO-8859-7");
251         }
252         if (isEncodingSupported("ISO-8859-8")) {
253             ControlSequence rightHalf = // high bit on, leave on
254                 new ControlSequence(new byte[] { 0x1B, 0x2D, 0x48 });
255             tSequenceToEncodingMap.put(rightHalf, "ISO-8859-8");
256             tHighBitsMap.put(rightHalf, Boolean.TRUE);
257 
258             ControlSequence fullSet = leftAscii.concatenate(rightHalf);
259             tEncodingToSequenceMap.put("ISO-8859-8", fullSet);
260             tEncodings.add("ISO-8859-8");
261         }
262         if (isEncodingSupported("ISO-8859-9")) {
263             ControlSequence rightHalf = // high bit on, leave on
264                 new ControlSequence(new byte[] { 0x1B, 0x2D, 0x4D });
265             tSequenceToEncodingMap.put(rightHalf, "ISO-8859-9");
266             tHighBitsMap.put(rightHalf, Boolean.TRUE);
267 
268             ControlSequence fullSet = leftAscii.concatenate(rightHalf);
269             tEncodingToSequenceMap.put("ISO-8859-9", fullSet);
270             tEncodings.add("ISO-8859-9");
271         }
272         if (isEncodingSupported("JIS_X0201")) {
273             ControlSequence glLeft = // high bit off, leave off
274                 new ControlSequence(new byte[] { 0x1B, 0x28, 0x4A });
275             ControlSequence glRight = // high bit off, turn on
276                 new ControlSequence(new byte[] { 0x1B, 0x28, 0x49 });
277             ControlSequence grLeft = // high bit on, turn off
278                 new ControlSequence(new byte[] { 0x1B, 0x29, 0x4A });
279             ControlSequence grRight = // high bit on, leave on
280                 new ControlSequence(new byte[] { 0x1B, 0x29, 0x49 });
281             tSequenceToEncodingMap.put(glLeft, "JIS_X0201");
282             tSequenceToEncodingMap.put(glRight, "JIS_X0201");
283             tSequenceToEncodingMap.put(grLeft, "JIS_X0201");
284             tSequenceToEncodingMap.put(grRight, "JIS_X0201");
285             tHighBitsMap.put(glLeft, Boolean.FALSE);
286             tHighBitsMap.put(glRight, Boolean.TRUE);
287             tHighBitsMap.put(grLeft, Boolean.FALSE);
288             tHighBitsMap.put(grRight, Boolean.TRUE);
289 
290             ControlSequence fullSet = glLeft.concatenate(grRight);
291             tEncodingToSequenceMap.put("JIS_X0201", fullSet);
292             tEncodings.add("JIS_X0201");
293         }
294         if (isEncodingSupported("X11GB2312")) {
295             ControlSequence leftHalf =  // high bit off, leave off
296                 new ControlSequence(new byte[] { 0x1B, 0x24, 0x28, 0x41 });
297             ControlSequence rightHalf = // high bit on, turn off
298                 new ControlSequence(new byte[] { 0x1B, 0x24, 0x29, 0x41 });
299             tSequenceToEncodingMap.put(leftHalf, "X11GB2312");
300             tSequenceToEncodingMap.put(rightHalf, "X11GB2312");
301             tHighBitsMap.put(leftHalf, Boolean.FALSE);
302             tHighBitsMap.put(rightHalf, Boolean.FALSE);
303 
304             tEncodingToSequenceMap.put("X11GB2312", leftHalf);
305             tEncodings.add("X11GB2312");
306         }
307         if (isEncodingSupported("x-JIS0208")) {
308             ControlSequence leftHalf = // high bit off, leave off
309                 new ControlSequence(new byte[] { 0x1B, 0x24, 0x28, 0x42 });
310             ControlSequence rightHalf = // high bit on, turn off
311                 new ControlSequence(new byte[] { 0x1B, 0x24, 0x29, 0x42 });
312             tSequenceToEncodingMap.put(leftHalf, "x-JIS0208");
313             tSequenceToEncodingMap.put(rightHalf, "x-JIS0208");
314             tHighBitsMap.put(leftHalf, Boolean.FALSE);
315             tHighBitsMap.put(rightHalf, Boolean.FALSE);
316 
317             tEncodingToSequenceMap.put("x-JIS0208", leftHalf);
318             tEncodings.add("x-JIS0208");
319         }
320         if (isEncodingSupported("X11KSC5601")) {
321             ControlSequence leftHalf = // high bit off, leave off
322                 new ControlSequence(new byte[] { 0x1B, 0x24, 0x28, 0x43 });
323             ControlSequence rightHalf = // high bit on, turn off
324                 new ControlSequence(new byte[] { 0x1B, 0x24, 0x29, 0x43 });
325             tSequenceToEncodingMap.put(leftHalf, "X11KSC5601");
326             tSequenceToEncodingMap.put(rightHalf, "X11KSC5601");
327             tHighBitsMap.put(leftHalf, Boolean.FALSE);
328             tHighBitsMap.put(rightHalf, Boolean.FALSE);
329 
330             tEncodingToSequenceMap.put("X11KSC5601", leftHalf);
331             tEncodings.add("X11KSC5601");
332         }
333 
334         // Encodings not listed in Compound Text Encoding spec
335 
336         // Esc seq: -b
337         if (isEncodingSupported("ISO-8859-15")) {
338             ControlSequence rightHalf = // high bit on, leave on
339                 new ControlSequence(new byte[] { 0x1B, 0x2D, 0x62 });
340             tSequenceToEncodingMap.put(rightHalf, "ISO-8859-15");
341             tHighBitsMap.put(rightHalf, Boolean.TRUE);
342 
343             ControlSequence fullSet = leftAscii.concatenate(rightHalf);
344             tEncodingToSequenceMap.put("ISO-8859-15", fullSet);
345             tEncodings.add("ISO-8859-15");
346         }
347         // Esc seq: -T
348         if (isEncodingSupported("TIS-620")) {
349             ControlSequence rightHalf = // high bit on, leave on
350                 new ControlSequence(new byte[] { 0x1B, 0x2D, 0x54 });
351             tSequenceToEncodingMap.put(rightHalf, "TIS-620");
352             tHighBitsMap.put(rightHalf, Boolean.TRUE);
353 
354             ControlSequence fullSet = leftAscii.concatenate(rightHalf);
355             tEncodingToSequenceMap.put("TIS-620", fullSet);
356             tEncodings.add("TIS-620");
357         }
358         if (isEncodingSupported("JIS_X0212-1990")) {
359             ControlSequence leftHalf = // high bit off, leave off
360                 new ControlSequence(new byte[] { 0x1B, 0x24, 0x28, 0x44 });
361             ControlSequence rightHalf = // high bit on, turn off
362                 new ControlSequence(new byte[] { 0x1B, 0x24, 0x29, 0x44 });
363             tSequenceToEncodingMap.put(leftHalf, "JIS_X0212-1990");
364             tSequenceToEncodingMap.put(rightHalf, "JIS_X0212-1990");
365             tHighBitsMap.put(leftHalf, Boolean.FALSE);
366             tHighBitsMap.put(rightHalf, Boolean.FALSE);
367 
368             tEncodingToSequenceMap.put("JIS_X0212-1990", leftHalf);
369             tEncodings.add("JIS_X0212-1990");
370         }
371         if (isEncodingSupported("X11CNS11643P1")) {
372             ControlSequence leftHalf = // high bit off, leave off
373                 new ControlSequence(new byte[] { 0x1B, 0x24, 0x28, 0x47 });
374             ControlSequence rightHalf = // high bit on, turn off
375                 new ControlSequence(new byte[] { 0x1B, 0x24, 0x29, 0x47 });
376             tSequenceToEncodingMap.put(leftHalf, "X11CNS11643P1");
377             tSequenceToEncodingMap.put(rightHalf, "X11CNS11643P1");
378             tHighBitsMap.put(leftHalf, Boolean.FALSE);
379             tHighBitsMap.put(rightHalf, Boolean.FALSE);
380 
381             tEncodingToSequenceMap.put("X11CNS11643P1", leftHalf);
382             tEncodings.add("X11CNS11643P1");
383         }
384         if (isEncodingSupported("X11CNS11643P2")) {
385             ControlSequence leftHalf = // high bit off, leave off
386                 new ControlSequence(new byte[] { 0x1B, 0x24, 0x28, 0x48 });
387             ControlSequence rightHalf = // high bit on, turn off
388                 new ControlSequence(new byte[] { 0x1B, 0x24, 0x29, 0x48 });
389             tSequenceToEncodingMap.put(leftHalf, "X11CNS11643P2");
390             tSequenceToEncodingMap.put(rightHalf, "X11CNS11643P2");
391             tHighBitsMap.put(leftHalf, Boolean.FALSE);
392             tHighBitsMap.put(rightHalf, Boolean.FALSE);
393 
394             tEncodingToSequenceMap.put("X11CNS11643P2", leftHalf);
395             tEncodings.add("X11CNS11643P2");
396         }
397         if (isEncodingSupported("X11CNS11643P3")) {
398             ControlSequence leftHalf = // high bit off, leave off
399                 new ControlSequence(new byte[] { 0x1B, 0x24, 0x28, 0x49 });
400             ControlSequence rightHalf = // high bit on, turn off
401                 new ControlSequence(new byte[] { 0x1B, 0x24, 0x29, 0x49 });
402             tSequenceToEncodingMap.put(leftHalf, "X11CNS11643P3");
403             tSequenceToEncodingMap.put(rightHalf, "X11CNS11643P3");
404             tHighBitsMap.put(leftHalf, Boolean.FALSE);
405             tHighBitsMap.put(rightHalf, Boolean.FALSE);
406 
407             tEncodingToSequenceMap.put("X11CNS11643P3", leftHalf);
408             tEncodings.add("X11CNS11643P3");
409         }
410         // Esc seq: %/2??SUN-KSC5601.1992-3
411         if (isEncodingSupported("x-Johab")) {
412             // 0x32 looks wrong. It's copied from the Sun X11 Compound Text
413             // support code. It implies that all Johab characters comprise two
414             // octets, which isn't true. Johab supports the ASCII/KS-Roman
415             // characters from 0x21-0x7E with single-byte representations.
416             ControlSequence johab = new ControlSequence(
417                 new byte[] { 0x1b, 0x25, 0x2f, 0x32 },
418                 new byte[] { 0x53, 0x55, 0x4e, 0x2d, 0x4b, 0x53, 0x43, 0x35,
419                              0x36, 0x30, 0x31, 0x2e, 0x31, 0x39, 0x39, 0x32,
420                              0x2d, 0x33 });
421             tSequenceToEncodingMap.put(johab, "x-Johab");
422             tEncodingToSequenceMap.put("x-Johab", johab);
423             tEncodings.add("x-Johab");
424         }
425         // Esc seq: %/2??SUN-BIG5-1
426         if (isEncodingSupported("Big5")) {
427             // 0x32 looks wrong. It's copied from the Sun X11 Compound Text
428             // support code. It implies that all Big5 characters comprise two
429             // octets, which isn't true. Big5 supports the ASCII/CNS-Roman
430             // characters from 0x21-0x7E with single-byte representations.
431             ControlSequence big5 = new ControlSequence(
432                 new byte[] { 0x1b, 0x25, 0x2f, 0x32 },
433                 new byte[] { 0x53, 0x55, 0x4e, 0x2d, 0x42, 0x49, 0x47, 0x35,
434                              0x2d, 0x31 });
435             tSequenceToEncodingMap.put(big5, "Big5");
436             tEncodingToSequenceMap.put("Big5", big5);
437             tEncodings.add("Big5");
438         }
439 
440         sequenceToEncodingMap =
441             Collections.unmodifiableMap(tSequenceToEncodingMap);
442         highBitsMap = Collections.unmodifiableMap(tHighBitsMap);
443         encodingToSequenceMap =
444             Collections.unmodifiableMap(tEncodingToSequenceMap);
445         encodings = Collections.unmodifiableList(tEncodings);
446     }
447 
448     private static boolean isEncodingSupported(String encoding) {
449         try {
450             if (Charset.isSupported(encoding))
451                 return true;
452         } catch (IllegalArgumentException x) { }
453         return (getDecoder(encoding) != null &&
454                 getEncoder(encoding) != null);
455     }
456 
457 
458     // For Decoder
459     static CharsetDecoder getStandardDecoder(byte[] escSequence) {
460         return getNonStandardDecoder(escSequence, null);
461     }
462     static boolean getHighBit(byte[] escSequence) {
463         Boolean bool = highBitsMap.get(new ControlSequence(escSequence));
464         return (bool == Boolean.TRUE);
465     }
466     static CharsetDecoder getNonStandardDecoder(byte[] escSequence,
467                                                        byte[] encoding) {
468         return getDecoder(sequenceToEncodingMap.get
469             (new ControlSequence(escSequence, encoding)));
470     }
471     static CharsetDecoder getDecoder(String enc) {
472         if (enc == null) {
473             return null;
474         }
475         Charset cs = null;
476         try {
477             cs = Charset.forName(enc);
478         } catch (IllegalArgumentException e) {
479             Class<?> cls;
480             try {
481                 cls = Class.forName("sun.awt.motif." + enc);
482             } catch (ClassNotFoundException ee) {
483                 return null;
484             }
485             try {
486                 cs = (Charset)cls.newInstance();
487             } catch (InstantiationException ee) {
488                 return null;
489             } catch (IllegalAccessException ee) {
490                 return null;
491             }
492         }
493         try {
494             return cs.newDecoder();
495         } catch (UnsupportedOperationException e) {}
496         return null;
497     }
498 
499 
500     // For Encoder
501     static byte[] getEscapeSequence(String encoding) {
502         ControlSequence seq = encodingToSequenceMap.get(encoding);
503         if (seq != null) {
504             return seq.escSequence;
505         }
506         return null;
507     }
508     static byte[] getEncoding(String encoding) {
509         ControlSequence seq = encodingToSequenceMap.get(encoding);
510         if (seq != null) {
511             return seq.encoding;
512         }
513         return null;
514     }
515     static List<String> getEncodings() {
516         return encodings;
517     }
518     static CharsetEncoder getEncoder(String enc) {
519         if (enc == null) {
520             return null;
521         }
522         Charset cs = null;
523         try {
524             cs = Charset.forName(enc);
525         } catch (IllegalArgumentException e) {
526             Class<?> cls;
527             try {
528                 cls = Class.forName("sun.awt.motif." + enc);
529             } catch (ClassNotFoundException ee) {
530                 return null;
531             }
532             try {
533                 cs = (Charset)cls.newInstance();
534             } catch (InstantiationException ee) {
535                 return null;
536             } catch (IllegalAccessException ee) {
537                 return null;
538             }
539         }
540         try {
541             return cs.newEncoder();
542         } catch (Throwable e) {}
543         return null;
544     }
545 
546     // Not an instantiable class
547     private CompoundTextSupport() {}
548 }